<?php
declare (strict_types=1);

namespace app\common\model;

use Exception;
use think\Collection;
use think\facade\Cache;

class WebsiteConfig extends CommonBase
{
    private const _CACHE_KEY = '%s_website_configs';
    protected $name = 'config';
    public const CONFIG_GROUP_MAP = ['base' => '基础配置', 'email' => '邮件配置'];

    public function getAllWebsiteConfig(array $where = []): Collection
    {
        $where['is_delete'] = config('status.mysql.table_normal');
        return $this->where($where)->order('config_group asc,sort asc')->select();
    }

    public function getWebsiteConfigList(int $page = 1, int $limit = 10, array $where = []): Collection
    {
        $where['is_delete'] = config('status.mysql.table_normal');
        $offset             = ($page - 1) * $limit;
        return $this->where($where)->order('config_group asc,sort asc')->limit($offset, $limit)->select();
    }

    public function getWebsiteConfigCount(array $where = []): int
    {
        $where['is_delete'] = config('status.mysql.table_normal');
        return $this->where($where)->count();
    }

    public function findWebsiteConfigById(int $id)
    {
        return $this->where(['id' => $id, 'is_delete' => config('status.mysql.table_normal')])->find();
    }

    public function addWebsiteConfig(string $cdnDomain, array $data): bool
    {
        $row = $this->where(['is_delete' => config('status.mysql.table_delete'), 'config_code' => $data['config_code']])->find();
        if (!empty($row)) {
            $cur                  = $row->toArray();
            $data['config_value'] = '';
            $data['is_delete']    = config('status.mysql.table_normal');
            $data['created_at']   = date('Y-m-d H:i:s', time());
            $data['updated_at']   = date('Y-m-d H:i:s', time());
            return (boolean)$this->where(['id' => $cur['id']])->update($data);
        }

        return (boolean)$this->save($data) && $this->_updateWebsiteConfigInfo($cdnDomain);
    }

    public function updateWebsiteConfig(string $cdnDomain, int $id, array $data): bool
    {
        $data['updated_at'] = date('Y-m-d H:i:s');
        return (boolean)$this->where(['id' => $id])->save($data) && $this->_updateWebsiteConfigInfo($cdnDomain);
    }

    /**
     * @throws Exception
     */
    public function deleteWebsiteConfig(string $cdnDomain, int $id): bool
    {
        try {
            $this->startTrans();
            $this->where(['id' => $id])->save(['is_delete' => config('status.mysql.table_delete')]);
            $this->name('attachment')->where(['relation_id' => $id, 'relation_type' => self::WEBSITE_CONFIG_ATTACHMENT_TYPE])->update([
                'is_delete'  => config('status.mysql.table_delete'),
                'updated_at' => date('Y-m-d H:i:s'),
            ]);
            $this->_updateWebsiteConfigInfo($cdnDomain);
            $this->commit();
            return true;
        } catch (Exception $e) {
            $this->rollback();
            throw new Exception($e->getMessage());
        }
    }

    public function getWebsiteConfigInfo(string $cdnDomain): array
    {
        $websiteConfigs = Cache::get(sprintf(self::_CACHE_KEY, $this->connection));
        if (!empty($websiteConfigs)) {
            return $websiteConfigs;
        }

        return $this->_updateWebsiteConfigInfo($cdnDomain);
    }

    private function _updateWebsiteConfigInfo(string $cdnDomain): array
    {
        $websiteConfigs = [];
        $rows           = $this->getAllWebsiteConfig()->toArray();
        foreach ($rows as $row) {
            if ($row['field_type'] == 'image' || $row['field_type'] == 'file') {
                $row['config_value'] = $row['config_value'] ? $cdnDomain . '/' . $row['config_value'] : '';
            }
            $websiteConfigs[$row['config_code']] = $row['config_value'];
        }

        Cache::set(sprintf(self::_CACHE_KEY, $this->connection), $websiteConfigs, self::CACHE_EXPIRE_TIME);
        return $websiteConfigs;
    }

    /**
     * @throws Exception
     */
    public function batchUpdateWebsiteConfigByCode($cdnDomain, $data): bool
    {
        try {
            $this->startTrans();
            $configs   = $this->getAllWebsiteConfig();
            $configMap = [];
            foreach ($configs as $config) {
                $configMap[$config['config_code']] = $config;
            }

            foreach ($data as $v) {
                $this->where(['config_code' => $v['config_code']])->save(['config_value' => $v['config_value']]);

                $config = $configMap[$v['config_code']] ?? [];
                if (!empty($config) && ($config['field_type'] == 'image' || $config['field_type'] == 'file')) {
                    $this->name('attachment')->where(['url_md5' => md5($v['config_value'])])->update([
                        'relation_type' => self::WEBSITE_CONFIG_ATTACHMENT_TYPE,
                        'relation_id'   => $config['id'],
                        'updated_at'    => date('Y-m-d H:i:s'),
                    ]);
                }
            }

            $this->commit();

            $cacheData = [];
            foreach ($data as $v) {
                $config = $configMap[$v['config_code']] ?? [];
                if (empty($config)) {
                    continue;
                }

                $cacheData[$v['config_code']] = $v['config_value'];
                if ($config['field_type'] == 'image' || $config['field_type'] == 'file') {
                    $cacheData[$v['config_code']] = $v['config_value'] ? $cdnDomain . '/' . $v['config_value'] : '';
                }
            }

            Cache::set(sprintf(self::_CACHE_KEY, $this->connection), $cacheData, self::CACHE_EXPIRE_TIME);

            return true;

        } catch (Exception $e) {
            $this->rollback();
            throw new Exception($e->getMessage());
        }
    }

    public function findWebsiteConfigByCode(string $code)
    {
        return $this->where(['config_code' => $code, 'is_delete' => config('status.mysql.table_normal')])->find();
    }

    /**
     * @throws Exception
     */
    public function batchWebsiteConfigSort(array $data): bool
    {
        try {
            $this->startTrans();
            foreach ($data as $id => $sort) {
                $this->where('id', $id)->update(['sort' => $sort]);
            }
            $this->commit();
            return true;
        } catch (Exception $e) {
            $this->rollback();
            throw new Exception($e->getMessage());
        }
    }
}
